package cn.tedu.lucky.draw.server.job.config;

import cn.tedu.lucky.draw.server.job.listener.ActivityDBToCsvJobListener;
import cn.tedu.lucky.draw.server.job.processor.ActivityItemProcessor;
import cn.tedu.lucky.draw.server.protocol.po.Activity;
import cn.tedu.lucky.draw.server.repository.ActivityRepository;
import com.alibaba.druid.sql.ast.SQLPartitionSpec;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.data.RepositoryItemWriter;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.PathResource;

import java.io.File;

@Configuration
public class CsvToDBJobConfig {

    /**
     * Job构建工厂
     */
    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Autowired
    private ActivityRepository activityRepository;

    //定义ItemReader 从CSV文件读取数据
    @Bean
    public ItemReader<Activity> itemReader() {
        return new FlatFileItemReaderBuilder<Activity>()
                .name("itemReader") //设置reader的名称
                .saveState(false) //设置是否保存状态,如果作业失败重启，是否会从上次失败的位置继续执行
                .resource(new PathResource(new File("doc/activity.csv").getAbsolutePath()))
                .delimited() //指定这个文件是用分隔符分割的文本
                .names("name", "description", "img", "status", "sort")//定义CSV文件中每列数据对应的字段名
                .targetType(Activity.class) //设置读取的数据类型
                .linesToSkip(1)//跳过第一行,通常第一行是标题行
                .build();//完成配置并构建实例对象
    }

    @Bean
    public ItemProcessor<Activity, Activity> itemProcessor() {
        return new ActivityItemProcessor();
    }

    @Bean
    public ItemWriter<Activity> itemWriter() {
        /**
         * 创建一个RepositoryItemWriter的实例
         * RepositoryItemWriter是专门为Spring Data JPA提供的ItemWriter实现类，与Repository接口配合使用，可以将数据保存到数据库中。
         */
        RepositoryItemWriter<Activity> activityRepositoryItemWriter = new RepositoryItemWriter<>();
        /**
         * 指定activityRepositoryItemWriter使用哪个repository保存数据
         * 将activityRepository实例注入到activityRepositoryItemWriter中
         */
        activityRepositoryItemWriter.setRepository(activityRepository);
        /**
         * 指定activityRepositoryItemWriter调用哪个方法保存数据
         * 当writer写入数据时，都会调用这个方法，将数据保存到数据库中
         */
        activityRepositoryItemWriter.setMethodName("save");
        return activityRepositoryItemWriter;
    }

    @Bean
    public Step csvToDBStep() {
        return stepBuilderFactory.get("csvToDBStep")
                /**
                 * 定义块大小，也就是每次处理的数据项的数量
                 * 这里设置为10000，表示每次处理10000条数据
                 */
                .<Activity, Activity>chunk(10000) //设置每批处理的记录数
                .reader(itemReader()) //设置itemReader
                .processor(itemProcessor()) //设置itemProcessor
                .writer(itemWriter()) //设置itemWriter
                .build();
    }

    @Bean
    public JobExecutionListener listener() {
        return new ActivityDBToCsvJobListener();
    }

    //定义JOB
    @Bean
    public Job csvToDBJob() {
        /**
         * 定义一个新得JOB实例
         */
        return jobBuilderFactory.get("csvToDBJob")
                /**
                 * 定义这个JOB包含哪些Step
                 */
                .start(csvToDBStep())
                /**
                 * 设置一个运行ID增量器
                 * RunIdIncrementer会为每个运行创建一个唯一的ID，并将其作为该运行的标识符。
                 */
                .incrementer(new RunIdIncrementer())
                /**
                 * 为作业添加一个监听器，用于监控作业的执行情况
                 */
                .listener(listener())
                .build();
    }
}
